#ifndef __FINITE_STATE_MACHINE_H__
#define __FINITE_STATE_MACHINE_H__

#include "common.h"
#include <set>
#include <map>
#include <stdarg.h>

#define BEG_DEF_NAMESPACE_FSM	\
	BEG_DEF_NAMESPACE_GLOBAL\
		namespace fsm{

#define END_DEF_NAMESPACE_FSM	\
		}		\
	END_DEF_NAMESPACE_GLOBAL

#define USE_NAMESPACE_FSM	\
	using namespace GLOBAL_NS::fsm;

BEG_DEF_NAMESPACE_FSM

#define OK			0 /* ok */
#define ERR			1 /* general error,mostly to be used for checking the return value */
#define ERR_STATE_DUPLICATE	2 /* already exist the same state code */
#define ERR_STATE_NOTEXIST 	3 /* the specific state code don't exist*/
#define ERR_STATE_INVALID	4 /* the mCurrStateCode is invalid */
#define ERR_NOT_SUB_STATE	5

typedef int FSM_STATE_CODE ;
#define BEFORE_BEGIN -1
#define AFTER_END -2
#define ISVALIDSTATE( STATE )	(STATE > BEFORE_BEGIN)

class FSMState;
typedef std::set< FSM_STATE_CODE > FSM_STATE_CODE_SET;
typedef FSM_STATE_CODE (* FSM_ACTION)( FSMState * pState , void * pData );

class FSMState{
public:
	FSMState();
	/** 
	 * @brief assemble the current state with the parameters
	 * 
	 * @param stateCode 	the state code of current state
	 * @param action	the action of currenassemblet state
	 * @param ...		the substate code of current state
	 * 
	 * @return 
	 */
	int BuildState( FSM_STATE_CODE stateCode , FSM_ACTION action , ... );
private:
	bool IsSubStateCode( FSM_STATE_CODE stateCode );
private:
	FSM_STATE_CODE mStateCode;
	FSM_STATE_CODE_SET mSubStateCodeSet;
private:
	friend class FSM;
	FSM_ACTION Action;
};

typedef std::map< FSM_STATE_CODE , FSMState * > FSM_STATE_MAP;
class FSM{
public:
	FSM();
	int Trigger( void * pData );
	int BuildFSM( FSM_STATE_CODE beginStateCode , FSM_STATE_CODE endStateCode , ... );

private:
	int	CheckState( FSM_STATE_CODE stateCode , FSMState ** ppState);
	FSMState * FindState( FSM_STATE_CODE stateCode );
private:
	FSM_STATE_CODE mCurrStateCode;
	FSM_STATE_CODE mBeginStateCode;
	FSM_STATE_CODE mEndStateCode;

	FSM_STATE_MAP  mStateMap;
};

#define CreateFSMState( VARIABLE , STATECODE , ACTION , ... ) \
	FSMState *VARIABLE = new FSMState();VARIABLE->BuildState( STATECODE , ACTION ,__VA_ARGS__)

END_DEF_NAMESPACE_FSM

#endif
